/* *****************************************************************************

 Copyright (C) : 2000-2024, unit

 ******************************************************************************
 File Name     : tcp_video.c
 Version       : ver 1.0
 Author        : phh
 Created       : 2024/10/14
 Last Modified :
 Description   :
 Function List :
 History       :
 1.Date        : 2024/10/14
   Author      : phh
   Modification: Created file

***************************************************************************** */

/* ----------------------------------------------*
 * header files                                  *
 *---------------------------------------------- */
#include "tcp_video.h"

#include "utlist.h"
#include "osal_file.h"

//#include "config.h"
#include <k_api.h>
#include "video_app.h"
#include <csi_kernel.h>
#include "lwip/sockets.h"
#include "lwip/priv/sockets_priv.h"
#include "lwip/api.h"
#include "stream_frame.h"
#include "jpgdef.h"



#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

/* ----------------------------------------------*
 * macro                                         *
 *---------------------------------------------- */
#define		UTR308_TCP_PORT			8899
#define		UTR308_CONTROL_PORT			9010
	
#define USE_TCP_EN 				1

/* ----------------------------------------------*
 * type definition                               *
 *---------------------------------------------- */

/* ----------------------------------------------*
 * module-wide global variables                  *
 *---------------------------------------------- */

int tcpSocket=-1;
static bool flag=false;
struct sockaddr_in udp_service_addr,udp_client_addr;
struct sockaddr_in udp_broadcast_addr;


static stream *tcp_s;

/* ----------------------------------------------*
 * modul global variables                        *
 *---------------------------------------------- */
k_task_handle_t frame_udp_handle;
k_task_handle_t test_udp_handle;

k_task_handle_t uvc_thread_handle;
k_task_handle_t tcp_thread_handle;
k_task_handle_t tcp_control_handle;

k_mutex_handle_t mutSem;

/* ----------------------------------------------*
 * internal routine prototypes                   *
 *---------------------------------------------- */

/* ----------------------------------------------*
 * routines' implementations                     *
 *---------------------------------------------- */






void tcp_demo_thread(void)
{

    int tcp_socket_fd, client_fd;
    int err = -1;
    uint8 receive_buf[40];
    char ipbuf[64] = {0};


    struct sockaddr_in tcp_service_addr, tcp_client_addr;
    uint32_t addrlen = sizeof(struct sockaddr_in);

    printf("sizeof(receive_buf)=%d\n",sizeof(receive_buf));
    //receive_buf[10]=10;
    printf("receive_buf[10]=%d\n",receive_buf[10]);
    // Create TCP socket
    tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcp_socket_fd < 0)
    {
        printf("Failed to create TCP socket\n");
        return;
    }


    // Bind socket to address and port
    tcp_service_addr.sin_family = AF_INET;
    tcp_service_addr.sin_port = htons(UTR308_TCP_PORT);  // Define TCP_PORT as needed
    tcp_service_addr.sin_addr.s_addr = INADDR_ANY; // Listen on all available interfaces
    //setsockopt

    err = bind(tcp_socket_fd, (struct sockaddr*)&tcp_service_addr, sizeof(struct sockaddr_in));
    if (err == -1)
    {
        printf("Bind error\n");
        close(tcp_socket_fd);
        return;
    }

    // Listen for incoming connections
    err = listen(tcp_socket_fd, 1);  // Maximum 5 pending connections
    if (err == -1)
    {
        printf("Listen error\n");
        close(tcp_socket_fd);
        return;
    }

    printf("Server listening on port %d...\n", UTR308_TCP_PORT);
    //set_socket_nonblocking(tcp_socket_fd);
    while (1)
    {


        printf("waitting accept\r\n");

        // Accept incoming connection
        client_fd = accept(tcp_socket_fd, (struct sockaddr*)&tcp_client_addr, &addrlen);
        if (client_fd < 0)
        {
            printf("Accept error\n");
            continue;
        }

        printf("Client connected: %s, port %d\n",
               inet_ntop(AF_INET, &tcp_client_addr.sin_addr, ipbuf, sizeof(ipbuf)),
               ntohs(tcp_client_addr.sin_port));


        tcpSocket=client_fd;

        // Handle client communication
        while (1)
        {

            // Receive data from client
            err = recv(client_fd, receive_buf,sizeof(receive_buf), 0);

            if (err <= 0)
            {
                //不可以CLOSE，必须等待uvc线程发送失败后
                //close(client_fd);
                tcpSocket=-1;


                break;  // Exit inner loop and wait for new connections
            }
			else
			{
				send(client_fd, receive_buf, err, 0);
			}

            os_sleep_ms(100);
        }
    }
}


void Uvc_Handle_Thread(void)
{
    k_status_t status;
    k_task_handle_t task_owner;
    uint8_t resend;

    int32_t uploadTime=os_jiffies();
    int ret = 0;
    uint8_t index = 0;

    tcp_s = open_stream_available(R_RTP_JPEG,0,8,NULL,NULL);

    struct data_structure  *data_f = NULL;
    uint32_t node_len,jpg_size,send_len;
    uint32_t* jpg_addr_buf = NULL;
    int data_len = 0;
    uint32_t photo_len = 0;

    int tcp_fd=-1;

    uint8_t frame_loss = 0;
    volatile uint32_t test_total_len = 0;
    u8_t video_enable = 0;
    uint8_t *malloc_buf = NULL;
    if(tcp_s)
    {
        jpeg_stream_init();
        //enable_stream(tcp_s,1);
        //video_enable = 1;
    }


    //os_printf("#malloc %d\n",jpg_size);

    malloc_buf = (uint8_t*)os_malloc(4200 );
    if(malloc_buf==NULL)
        goto uvc_thread_end;



    while(1)
    {
		if ( tcpSocket<0 )
		{
		    goto uvc_end;
		}
		else
		{
			if ( !video_enable )
			{
				tcp_fd=tcpSocket;
				enable_stream(tcp_s,1);
				
				video_enable = 1;
			}
			else
			{
			    
			}

		}

#if 0
        switch ( uvcMode )
        {
        case 0:
            //先判断图传使能是否开启,再进行图传
            if ( stSys.uvcEn )
            {
                //等待开启
                uvcMode=1;
                tcp_fd=tcpSocket;
                os_printf("uvcMode = %d\n",uvcMode);
            }
            goto uvc_end;
            break;
        case 1:
            //如果关闭
            if ( !stSys.uvcEn)
            {
                //进入等待再次开启
                uvcMode=2;
                //关闭流
                if(data_f)
                {
                    DEL_JPG_FRAME(data_f);
                    data_f = NULL;
                }
                close_stream(tcp_s);

                os_printf("uvcMode = %d\n",uvcMode);
                goto uvc_end;
            }
            break;
        case 2:
            //如果开启
            if ( stSys.uvcEn)
            {
                //再次进入工作状态
                uvcMode=1;
                //赋予SOCK
                tcp_fd=tcpSocket;
                //再次打开流
                tcp_s = open_stream_available(R_RTP_JPEG,0,2,NULL,NULL);
                if(tcp_s)
                {
                    enable_stream(tcp_s,1);
                    video_enable = 1;
                }

                os_printf("uvcMode = %d\n",uvcMode);
            }
            else
            {
                goto uvc_end;
            }
            break;
        default:
            break;
        }
#endif /* 1 */



#if 1
        data_f = GET_FRAME(tcp_s);
        if(data_f)
        {
            //_os_printf("+");
            index = 0;
            test_total_len = 0;
            resend=0;
            node_len = GET_NODE_LEN(data_f);
            jpg_size = GET_DATA_LEN(data_f);
            jpg_addr_buf  =  (uint32_t*)GET_JPG_BUF(data_f);

            //os_printf("node_len = %d,jpg_size = %d  %x-----\n",node_len,jpg_size,*jpg_addr_buf);


            // os_printf("T:%d,J:%d %x,%x  %x,%x-----\n",test_total_len,jpg_size,jpg_addr_buf[0],jpg_addr_buf[1],g_jpeg_buf[0],g_jpeg_buf[1]);



            if (node_len >= jpg_size)  //PSRAM node_len就是一张图片的大小
            {
                data_len = node_len;
            }
            else if(node_len < jpg_size)	 // NO PSRAM
            {
                data_len = jpg_size;
            }
            photo_len = data_len;

#if 1
            if (data_len)
            {
                if (frame_loss == 0)
                {

                    while (data_len > 0)
                    {
                        if (data_len > 4096)
                            send_len = 4096;
                        else
                            send_len = data_len;
                        //os_printf("jpg_addr_buf[0] = 0x%x,jpg_addr_buf[photo_len-1] = 0x%x\r\n",*((uint8_t*)jpg_addr_buf),*((uint8_t*)jpg_addr_buf+photo_len-1) );
                        memset(malloc_buf,0,4200);
                        hw_memcpy0(malloc_buf,(uint8_t*)jpg_addr_buf + (index * 4096),send_len);
                        if ( tcpSocket<0 )
                        {
                            os_printf("tcpSocket:%d error\n",tcpSocket);

                            break;
                        }


                        ret = send(tcp_fd, malloc_buf, send_len, 0);


                        if (ret < 0)
                        {
                            resend++;
                            os_printf("resend:%d\n",resend);
                            if (resend >= 11)
                            {
                                frame_loss = 1;
                                break;
                            }
                            if ( tcp_fd<0 )
                            {
                                //os_printf("tcp_fd:%d error\n",tcp_fd);
                                break;
                            }
                            continue;
                        }
                        else
                        {
                            test_total_len += ret;
                            //printf("T:%d,%d,%d\n",test_total_len,ret,jpg_size);
                        }
                        index++;
                        data_len -= 4096;
                    }
                    if(test_total_len == photo_len)
                    {
                        //os_printf("T:%d,J:%d %x,%x  %x,%x-----\n",test_total_len,photo_len,jpg_addr_buf[0],jpg_addr_buf[1],malloc_buf[0],malloc_buf[1]);
                        // os_printf("Y\n");
                    }


                }
            }

#endif /* 0 */


            if (frame_loss == 1)
            {
                printf("**frame send err \n");
                frame_loss = 0;
            }

            if(data_f)
            {

                DEL_JPG_FRAME(data_f);
                data_f = NULL;
                //os_sleep_ms(100);
            }

        }
        else
        {
            //printf("GET_FRAME error\r\n");
        }
        if ( os_jiffies()>=uploadTime+1000 )
        {

            //os_sleep_ms(1);
            uploadTime=os_jiffies();


            //os_sleep_ms(1);

        }



#endif /* 0 */



uvc_end:

        os_sleep_ms(1);

    }
uvc_thread_end:
    if(data_f)
    {
        DEL_JPG_FRAME(data_f);
        data_f = NULL;
    }
    if(video_enable)
    {
        jpeg_stream_deinit(NULL);
    }
    if(tcp_s)
    {
        close_stream(tcp_s);
    }
    if(malloc_buf)
    {
        os_free(malloc_buf);
    }
    _os_printf("malloc_buf error");

}


void frame_test(void)
{

    csi_kernel_task_new((k_task_entry_t)Uvc_Handle_Thread, "Uvc_Handle_Thread", 0, 15, 0, NULL, 8192, &uvc_thread_handle);
    csi_kernel_task_new((k_task_entry_t)tcp_demo_thread, "tcp_demo_thread", 0, 16, 0, NULL, 8192, &tcp_thread_handle);
    //csi_kernel_task_new((k_task_entry_t)tcp_control_thread, "tcp_control_thread", 0, 16, 0, NULL, 4096, &tcp_control_handle);



}


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

